Add microsoft pushpin 2002 support. Courtesy Alex Mottram.
authorrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Tue, 10 Sep 2002 02:11:06 +0000 (02:11 +0000)
committerrobertl <robertl@f51c46e8-681c-474f-0cfe-069cfd0219fb>
Tue, 10 Sep 2002 02:11:06 +0000 (02:11 +0000)
gpsbabel/Makefile
gpsbabel/README
gpsbabel/psp.c [new file with mode: 0644]
gpsbabel/reference/ps.psp [new file with mode: 0644]
gpsbabel/testo
gpsbabel/vecs.c

index fdb0587c591f8de19f740389a86a7580444dc1d3..9eeabe5bdff52c404134e9074fa24ff0ad674248 100644 (file)
@@ -1,7 +1,8 @@
 CFLAGS=-g -Icoldsync
 
 FMTS=magproto.o gpx.o geo.o gpsman.o mapsend.o mapsource.o \
-       gpsutil.o tiger.o pcx.o csv.o cetus.o gpspilot.o magnav.o
+       gpsutil.o tiger.o pcx.o csv.o cetus.o gpspilot.o magnav.o \
+       psp.o
 
 OBJS=main.o queue.o route.o waypt.o util.o vecs.o mkshort.o \
        coldsync/util.o coldsync/pdb.o $(FMTS)
index afff15b47c86b2aa410155d68f798fe5fe3cf71f..6c23b32ff2f4f8ec3f3569c2b10c048f670633be 100644 (file)
@@ -98,6 +98,22 @@ THE FORMATS
        by Ron Parker.  GPSbabel can currently read gpspilot files, but not
        write them.
        
+    PSP
+       Microsoft's PocketStreets 2002 Pushpin (.PSP) format is not yet 
+       completely documented.  THE .PSP MODULE DOES NOT WORK WITH MS 
+       STREETS & TRIPS 2002 .EST FILES.  To create .PSP files from 
+        Streets & Trips 2002, you will need to have PocketStreets support 
+       installed.  Please note that MS Streets & Trips only *EXPORTS* 
+       .PSP files. It does not import them.  MS Streets & Trips 2002 
+       only imports CSV files.  To use .PSP files, simply copy them 
+       over to the same folder on the mobile device as the map (.MPS), 
+       and open PocketStreets.  It should also be noted that in the case 
+       a pushpin is outside of the exported map area, the pin will be 
+       "grayed-out" and unused in PocketStreets.  This is a good thing 
+       as it allows us to create one big .PSP file that covers multiple 
+       .MPS files.  Unfortunately, you need one .PSP file for every 
+       .MPS file. :(
+
 
 COMMON USAGE
 
diff --git a/gpsbabel/psp.c b/gpsbabel/psp.c
new file mode 100644 (file)
index 0000000..19e8533
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+    PocketStreets 2002 Pushpin Files
+    Contributed to gpsbabel by Alex Mottram.
+    
+    Copyright (C) 2002 Robert Lipe, robertlipe@usa.net
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+
+ */
+
+#include "defs.h"
+
+#include <ctype.h>
+#include <math.h>  /* for M_PI */
+
+/*#define _DEBUG_PSP   1*/
+#define MAXPSPSTRINGSIZE       256
+#define MAXPSPOUTPUTPINS       8192   /* Any more points than this is ludicrous */
+
+static FILE *psp_file_in;
+static FILE *psp_file_out;
+
+#ifdef _DEBUG_PSP
+static void 
+dump_bufferstuff(char * header, char * buffer, int bufferlen)
+{
+    int i;
+
+    printf("%s\n--------\n", header);
+
+    for (i = 0 ; i < bufferlen ; i++) {
+       printf("%0.2X ", (unsigned char)buffer[i]);
+    } 
+    printf("\n");
+}
+#endif
+
+static char *
+buffer_washer(char * buff, int buffer_len)
+{
+    int i;
+    
+    for (i = 0 ; i < buffer_len - 1; i++) {
+       if (buff[i] == '\0') {
+           memcpy(&buff[i], &buff[i+1], buffer_len - i);
+           buffer_len--;
+           buff[buffer_len] = '\0';
+       }
+    }
+
+    return (buff);
+}
+
+static void
+psp_rd_init(const char *fname)
+{
+       psp_file_in = fopen(fname, "r");
+       if (psp_file_in == NULL) {
+               fatal("PSP: Cannot open %s for reading\n", fname);
+       }
+}
+
+static void
+psp_rd_deinit(void)
+{
+       fclose(psp_file_in);
+}
+
+static void
+psp_wr_init(const char *fname)
+{
+       psp_file_out = fopen(fname, "w");
+       if (psp_file_out == NULL) {
+               fatal("PSP: Cannot open %s for writing\n", fname);
+       }
+}
+
+static void
+psp_wr_deinit(void)
+{
+       fclose(psp_file_out);
+}
+
+static void
+psp_read(void)
+{
+       char buff[MAXPSPSTRINGSIZE + 1]; 
+       double radians;
+       waypoint *wpt_tmp;
+       int stringsize;
+       short int pincount;
+
+        /* 32 bytes - file header */
+        fread(&buff[0], 1, 32, psp_file_in);
+        
+       pincount = *(short int *)&buff[12];
+       
+       while (pincount--) {
+           wpt_tmp = calloc(sizeof(*wpt_tmp),1);
+
+           if (wpt_tmp == NULL) {
+               fatal("PSP: cannot allocate memory\n");
+           }
+
+           /* things we will probably never know about this waypoint */
+           /* coming from a pushpin file.                            */
+
+           /* 
+               wpt_tmp->creation_time;
+               wpt_tmp->position.altitude.altitude_meters;
+               wpt_tmp->url;
+               wpt_tmp->url_link_text;
+               wpt_tmp->icon_descr;  TODO: map this.
+           */
+           
+            /* 4 bytes at start of record */
+            /* coming out of S&T, this 1st byte is probably the pin # (0x01, 0x02, etc...) */
+            /* coming from pocketstreets, it's generally 0x00. Sometimes 0xC3. ?           */
+            
+           fread(&buff[0], 1, 4, psp_file_in);
+
+            /* 1 byte, unkown */
+            fread(&buff[0], 1, 1, psp_file_in);
+
+            /* 8 bytes - latitude in radians */
+            fread(&buff[0], 1, 8, psp_file_in);
+            radians = *(double *)&buff[0];
+            wpt_tmp->position.latitude.degrees = (radians * 180.0) / M_PI;
+
+            /* 8 bytes - longitude in radians */
+            fread(&buff[0], 1, 8, psp_file_in);
+            radians = *(double *)&buff[0];
+            wpt_tmp->position.longitude.degrees = (radians * 180.0) / M_PI;
+
+            /* 1 byte - pin display properties */
+            fread(&buff[0], 1, 1, psp_file_in);
+
+           /* 3 bytes - unknown */
+            fread(&buff[0], 1, 3, psp_file_in);
+
+           /* 1 bytes - icon 0x00 - 0x27 */
+            fread(&buff[0], 1, 1, psp_file_in);
+
+           /* 3 bytes - unknown */
+           fread(&buff[0], 1, 3, psp_file_in);
+
+            /* 1 byte - string size */
+           fread(&buff[0], 1, 1, psp_file_in);
+
+           stringsize = buff[0];
+           stringsize *= 2;
+           
+           if (stringsize > MAXPSPSTRINGSIZE) {
+               fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE);
+           }
+
+            /* stringsize bytes - string data */
+           fread(&buff[0], 1, stringsize, psp_file_in);
+
+           buffer_washer(buff, stringsize);
+
+#ifdef _DEBUG_PSP
+           printf ("string1: [%s]\n", buff);
+#endif             
+
+           wpt_tmp->shortname = strdup(buff);
+
+            /* 1 bytes string size */
+           fread(&buff[0], 1, 1, psp_file_in);
+
+           stringsize = buff[0];
+           stringsize *= 2;
+
+           if (stringsize > MAXPSPSTRINGSIZE) {
+               fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE);
+           }
+
+#ifdef _DEBUG_PSP
+           printf ("string2: there are %d bytes to follow at offset %ld\n", stringsize, ftell(psp_file_in));
+#endif
+
+            /* stringsize bytes - string data */            
+           fread(&buff[0], 1, stringsize, psp_file_in);
+
+           buffer_washer(buff, stringsize);
+
+#ifdef _DEBUG_PSP
+           printf ("string2: [%s]\n", buff);
+#endif
+           wpt_tmp->description = strdup(buff);
+
+            /* 1 bytes - string size */
+           fread(&buff[0], 1, 1, psp_file_in);
+
+           stringsize = buff[0];
+           stringsize *= 2;
+
+           if (stringsize > MAXPSPSTRINGSIZE) {
+               fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE);
+           }
+
+
+#ifdef _DEBUG_PSP
+           printf ("string: there are %d bytes to follow at offset %ld\n", stringsize, ftell(psp_file_in));
+#endif
+
+            /* stringsize bytes - string data (address?) */
+           fread(&buff[0], 1, stringsize, psp_file_in);
+
+           buffer_washer(buff, stringsize);
+
+#ifdef _DEBUG_PSP
+           printf ("string3: [%s]\n", buff);
+#endif             
+           
+           waypt_add(wpt_tmp);
+       } 
+
+
+}
+
+static void
+psp_disp(waypoint *wpt)
+{
+       double lon, lat;
+       char tbuf[64];
+       char c;
+       int i;
+
+        /* convert lat/long back to radians */
+       lat = (wpt->position.latitude.degrees * M_PI) / 180.0;
+        lon = (wpt->position.longitude.degrees * M_PI) / 180.0;
+
+        /* 4 leading bytes */
+        memset(&tbuf, '\0', sizeof(tbuf));
+        fwrite(&tbuf, 1, 4, psp_file_out);
+       
+        /* my test files seem to always have this byte as 0x03, */
+        /* although nothing seems to really care.               */
+       c = 0x03;
+       
+        /* 1 unknown bytes */
+        fwrite(&c, 1, 1, psp_file_out);
+
+        /* 8 bytes - latitude/radians */
+        fwrite(&lat, 1, 8, psp_file_out);
+
+        /* 8 bytes - longitude/radians */
+        fwrite(&lon, 1, 8, psp_file_out);
+
+        /* 1 byte - pin properties */
+        c = 0x14; /* display pin on! display notes on! */
+        fwrite(&c, 1, 1, psp_file_out);
+
+        memset(&tbuf, '\0', sizeof(tbuf));
+
+        /* 3 unknown bytes */
+        fwrite(&tbuf, 1, 3, psp_file_out); 
+
+        /* 1 icon byte 0x00 = PIN */
+        fwrite(&tbuf, 1, 1, psp_file_out);
+
+        /* 3 unknown bytes */
+        fwrite(&tbuf, 1, 3, psp_file_out); /* 3 junk */
+
+        c = strlen(wpt->shortname);
+        /* 1 string size */
+        fwrite(&c, 1, 1, psp_file_out); 
+
+        for (i = 0 ; wpt->shortname[i] ; i++) {
+             fwrite(&wpt->shortname[i], 1, 1, psp_file_out);    /* char */
+             fwrite(&tbuf[0], 1, 1, psp_file_out);              /* null */
+        }
+
+        /*  1 byte string size */
+        c = strlen(wpt->description);
+        fwrite(&c, 1, 1, psp_file_out);
+
+        for (i = 0 ; wpt->description[i] ; i++) {
+             fwrite(&wpt->description[i], 1, 1, psp_file_out);  /* char */
+             fwrite(&tbuf[0], 1, 1, psp_file_out);              /* null */
+        }
+
+        /* just for the hell of it, we'll scrap the third string. */
+        c = strlen(tbuf);
+        /* 1 byte string size */
+        fwrite(&c, 1, 1, psp_file_out); 
+
+        for (i = 0 ; tbuf[i] ; i++) {
+             fwrite(&tbuf[i], 1, 1, psp_file_out);              /* char */
+             fwrite(&tbuf[0], 1, 1, psp_file_out);              /* null */
+        }
+        
+}
+
+static void
+psp_write(void)
+{
+        short int s;
+       unsigned char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        /* the header: */
+        /* 31 6E 69 50 20 00 00 00 08 00 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */
+        /* offset 0x0C - 0x0D = 2 byte pin count */
+
+        s = waypt_count();
+        
+        if (s > MAXPSPOUTPUTPINS) {
+            fatal("attempt to output too many pushpins (%d).  The max is %d.  Sorry.\n", s, MAXPSPOUTPUTPINS);
+        }
+
+        /* insert waypoint count into header */
+        memcpy(&header_bytes[12], &s, 2);
+
+        fwrite(&header_bytes, 1,  32, psp_file_out);
+        
+        waypt_disp_all(psp_disp);
+}
+
+ff_vecs_t psp_vecs = {
+       psp_rd_init,
+       psp_wr_init,
+       psp_rd_deinit,
+       psp_wr_deinit,
+       psp_read,
+       psp_write,
+};
diff --git a/gpsbabel/reference/ps.psp b/gpsbabel/reference/ps.psp
new file mode 100644 (file)
index 0000000..4685ec5
Binary files /dev/null and b/gpsbabel/reference/ps.psp differ
index 73a7dedae23bceac444f577e5367c4a4c8531aa4..0bcc451af8676dbc1684afb06e86ea96011b34f1 100755 (executable)
@@ -54,3 +54,8 @@ diff /tmp/mm.gps /tmp/gu.wpt
 ${PNAME} -i magellan -f reference/magfile -o magellan -F /tmp/magfile
 diff /tmp/magfile reference/magfile
 
+
+# PSP (PocketStreets 2002 Pushpin (.PSP)) file format
+${PNAME} -i geo -f geocaching.loc -o psp -F /tmp/ps.psp
+diff /tmp/ps.psp reference
+
index e415193ae2d9a9afb3e0f478ab1e5ecc56cf71c9..ac044a4494dd13d80c79b955d1f8a0c282aa138e 100644 (file)
@@ -40,6 +40,7 @@ extern ff_vecs_t pcx_vecs;
 extern ff_vecs_t csv_vecs;
 extern ff_vecs_t cetus_vecs;
 extern ff_vecs_t gpspilot_vecs;
+extern ff_vecs_t psp_vecs;
 
 static
 vecs_t vec_list[] = {
@@ -93,6 +94,11 @@ vecs_t vec_list[] = {
                "csv",
                "Comma separated values"
        },
+       {
+               &psp_vecs,
+               "psp",
+               "MS PocketStreets 2002 Pushpin"
+       },
        {
                &cetus_vecs,
                "cetus",